﻿using HalconDotNet;
using MvCamCtrl.NET;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace YJYpublicClass
{
   public class HKCamera
    {
        MyCamera.MV_CC_DEVICE_INFO_LIST m_stDeviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
        static MyCamera.MV_CC_DEVICE_INFO_LIST m_stDeviceList2 = new MyCamera.MV_CC_DEVICE_INFO_LIST();
        
        public  static List<string> deviceName = new List<string>(); //存放对应相机的名字

        MyCamera.MV_CC_DEVICE_INFO stDevInfo;
        MyCamera.cbOutputExdelegate ImageCallback;  //定义回调函数

        private MyCamera m_MyCamera = new MyCamera();
        bool m_bGrabbing = false;

        MyCamera.MV_FRAME_OUT_INFO_EX m_stFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();

        // ch:用于从驱动获取图像的缓存 | en:Buffer for getting image from driver
        UInt32 m_nBufSizeForDriver = 0;
        IntPtr m_BufForDriver = IntPtr.Zero;
        private static Object BufForDriverLock = new Object();

        public HObject Image = null;
        public Boolean qututureFlag = false;
        public Boolean openflag = false;
        int openCameraflag = 1;
        public string resultMes = "";
        public HWindow m_Window;
        public Boolean GrabbingFlag = false;
        public Boolean IsUpdateView = true;
        public int grabCount = 0;
        public double heibilv = 1.5;
        
        public static void EnumeDevice()
        {
            try
            {
                m_stDeviceList2.nDeviceNum = 0;
                int nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE, ref m_stDeviceList2);
                //获取对应设备的序列号
                if (m_stDeviceList2.nDeviceNum <= 0)
                {
                    return;
                }
                
                for(int i=0;i<m_stDeviceList2.nDeviceNum;i++)
                {
                    //第一步先转换成device
                    MyCamera.MV_CC_DEVICE_INFO tempstDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList2.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
                    //第二步再去拿信息
                    MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(tempstDevInfo.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
                    //拿设备的序列号
                    deviceName.Add(gigeInfo.chSerialNumber);                                 
                }

            }
            catch (Exception)
            {
                            
            }
        }
        public Boolean openDevice()
        {
            try
            {
                m_stDeviceList.nDeviceNum = 0;
                int nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE, ref m_stDeviceList);
              // m_stDeviceList.pDeviceInfo.

                if (0 != nRet)
                {
                    MessageBox.Show("Enumerate devices fail!");
                    openflag = false;
                    return false;
                }
                if (m_stDeviceList.nDeviceNum<=0)
                {
                    MessageBox.Show("未检测到设备,请确保设备正常连接然后重启程序!");
                    openflag = false;
                    return false;
                }
                stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[0], typeof(MyCamera.MV_CC_DEVICE_INFO));
                //判断设备是否可访问
               //if( MyCamera.MV_CC_IsDeviceAccessible_NET(ref stDevInfo,1))
               //{
               //    MessageBox.Show("设备不可访问");
               //    openflag = false;
               //    return false;
               //}
                // ch:创建设备 | en:Create device
                nRet = m_MyCamera.MV_CC_CreateDevice_NET(ref stDevInfo);
                if (MyCamera.MV_OK != nRet)
                {
                    MessageBox.Show("未检测到设备,请确保设备正常连接然后重启程序!");
                    openflag = false;
                    return false;
                }

                // ch:打开设备 | en:Open device
                openCameraflag = m_MyCamera.MV_CC_OpenDevice_NET();
                if (MyCamera.MV_OK != openCameraflag)
                {
                    MessageBox.Show("打开设备失败");
                    openflag = false;
                    return false;
                }
                // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
                if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE)
                {
                    int nPacketSize = m_MyCamera.MV_CC_GetOptimalPacketSize_NET();
                    if (nPacketSize > 0)
                    {
                        nRet = m_MyCamera.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
                    }       
                }
                

                //初始化参数
                __InitParam();

                ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);

                //使用自带方法将回调函数作为参数输入，注册回调函数
                nRet = m_MyCamera.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
                if(nRet!=MyCamera.MV_OK)
                {

                    MessageBox.Show("注册失败");
                    openflag = false;
                    return false;
                }

                //开启触发模式

                if (m_MyCamera.MV_CC_StartGrabbing_NET() != MyCamera.MV_OK)
                {
                    MessageBox.Show("开始取图失败");
                    openflag = false;
                    return false;
                }
            
                openflag = true;
                return true;
            }
            catch (Exception ex)
            {

                resultMes = ex.ToString();
                openflag = false;
                return false;
            }

        }

       //
        public Boolean openDevice(string SerialNum)
        {
            try
            {
               
                //搜寻listname当中有没有这个序列号
                int index = deviceName.FindIndex(c=>c.Equals(SerialNum));
                if(index==-1)
                {
                    MessageBox.Show("未找到改序列号设备");
                    openflag = false;
                    return false;
                }
                //实例化需要的设备编号
                stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList2.pDeviceInfo[index], typeof(MyCamera.MV_CC_DEVICE_INFO));
                //判断设备是否可访问
                //if( MyCamera.MV_CC_IsDeviceAccessible_NET(ref stDevInfo,1))
                //{
                //    MessageBox.Show("设备不可访问");
                //    openflag = false;
                //    return false;
                //}
                // ch:创建设备 | en:Create device
                int  nRet = m_MyCamera.MV_CC_CreateDevice_NET(ref stDevInfo);
                if (MyCamera.MV_OK != nRet)
                {
                    MessageBox.Show("未检测到设备,请确保设备正常连接然后重启程序!");
                    openflag = false;
                    return false;
                }

                // ch:打开设备 | en:Open device
                openCameraflag = m_MyCamera.MV_CC_OpenDevice_NET();
                if (MyCamera.MV_OK != openCameraflag)
                {
                    MessageBox.Show("打开设备失败");
                    openflag = false;
                    return false;
                }
                // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
                if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE)
                {
                    int nPacketSize = m_MyCamera.MV_CC_GetOptimalPacketSize_NET();
                    if (nPacketSize > 0)
                    {
                        nRet = m_MyCamera.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
                    }
                }


                //初始化参数
                __InitParam();

                ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
                nRet = m_MyCamera.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
                if (nRet != MyCamera.MV_OK)
                {

                    MessageBox.Show("注册失败");
                    openflag = false;
                    return false;
                }
                //设置触发模式
                int net = m_MyCamera.MV_CC_SetEnumValue_NET("TriggerMode", 1);

                if (m_MyCamera.MV_CC_StartGrabbing_NET() != MyCamera.MV_OK)
                {
                    MessageBox.Show("开始取图失败");
                    openflag = false;
                    return false;
                }

                openflag = true;
                return true;
            }
            catch (Exception ex)
            {

                resultMes = ex.ToString();
                openflag = false;
                return false;
            }

        }
        //参数初始化,这个仅相当于硬线触发初始化
        public void __InitParam()
        {
            if(openCameraflag==0)
            {
                //设置触发模式
               int net= m_MyCamera.MV_CC_SetEnumValue_NET("TriggerMode", 0);
                //设置触发源
               m_MyCamera.MV_CC_SetEnumValue_NET("TriggerSource", 7);
                //设置下降沿
               // m_MyCamera.MV_CC_SetEnumValue_NET("TriggerActivation", 1);              
                //不设置延迟
                //关自动白平衡              
                //设置行频模式         
                //设置采集模式,连续采集
                //设置增益
               // m_MyCamera.MV_CC_SetFloatValue_NET("Gain", 4.9901f);
            }
  

        }
        public void setexposure(double exposuretime)
        {
            
            if (openCameraflag == 0)
            {    
                //设置曝光
                int nRet = m_MyCamera.MV_CC_SetFloatValue_NET("ExposureTime", (float)exposuretime);
                if (MyCamera.MV_OK != nRet)
                {
                    MessageBox.Show("曝光设置异常");    
                }
            }

        }
        public void setImageHeigt(UInt32 Imageheight)
        {
            if (openCameraflag == 0)
            {
                //设置曝光
                int nRet = m_MyCamera.MV_CC_SetIntValueEx_NET("Height", Imageheight);
                if (MyCamera.MV_OK != nRet)
                {
                    MessageBox.Show("高度设置异常");
                }
            }
        }

        public void setRowfreq(UInt32 Rowfreq)
        {
            if (openCameraflag == 0)
            {
                //设置曝光
                int nRet = m_MyCamera.MV_CC_SetIntValue_NET("AcquisitionLineRate", Rowfreq);
                if (MyCamera.MV_OK != nRet)
                {
                    MessageBox.Show("行频设置异常");
                }
            }
        }
        public void setLine1ON()
        {
            if (openCameraflag == 0)
            {
                //开选择1
                m_MyCamera.MV_CC_SetEnumValue_NET("LineSelector", 1);
                m_MyCamera.MV_CC_SetBoolValue_NET("LineInverter", true);
                //输出
               
            }

        }
        public void setLine1OFF()
        {
            if (openCameraflag == 0)
            {
                //开选择1
                m_MyCamera.MV_CC_SetEnumValue_NET("LineSelector", 1);
                m_MyCamera.MV_CC_SetBoolValue_NET("LineInverter", false);
                //输出
            }

        }
        //取图回调函数

        public Boolean startGrab()
        {
            if(openflag)
            {
                if (m_MyCamera.MV_CC_StartGrabbing_NET() != MyCamera.MV_OK)
                {                
                    GrabbingFlag = false;
                    return false;
                }
                else
                {
                    GrabbingFlag = true;
                    return true;
                }

            }else
            {
                return false;
            }
           
        }
        
        public Boolean stopGrab()
        {
            if(GrabbingFlag)
            {
                m_MyCamera.MV_CC_StopGrabbing_NET();
                GrabbingFlag = false;
                return true;
            }
            else
            {
                GrabbingFlag = false;
                return true;
            }
           
        }
        //切换为软触发
        public void SetsoftTrigger()
        {
            if (openCameraflag == 0)
            {
                //设置触发源为软触发
                m_MyCamera.MV_CC_SetEnumValue_NET("TriggerSource",7);
            }
        }
        //切换为硬线触发

        public void softTriggerExcute()   //软触发后，如何确定Image会获得当前图片？ qutuflag如何变化的？
        {
            if (openCameraflag == 0)
            {
                //软触发
                m_MyCamera.MV_CC_SetCommandValue_NET("TriggerSoftware");
            }
        }

        //关闭相机，释放资源
        public void CloseCamera()
        {
            
                // ch:停止抓图 | en:Stop grabbing
                int nRet =  m_MyCamera.MV_CC_StopGrabbing_NET();

                // ch:关闭设备 | en:Close device
                nRet =  m_MyCamera.MV_CC_CloseDevice_NET();

                // ch:销毁设备 | en:Destroy device
                nRet =  m_MyCamera.MV_CC_DestroyDevice_NET();
        }

        Stopwatch sw2 = new Stopwatch();
        IntPtr pTemp = IntPtr.Zero;
        IntPtr IpData = IntPtr.Zero;
        void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {

            sw2.Start();
            int nRet = 0;
            if (IpData == IntPtr.Zero)
            {
                IpData = Marshal.AllocHGlobal((int)pFrameInfo.nWidth * pFrameInfo.nHeight);
            }
            //分配指针空间
                   
           // IpData = Marshal.AllocHGlobal((int)g_nPayloadSize * 3);
            if (IsColorPixelFormat(pFrameInfo.enPixelType))
            {
                if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
                {
                    pTemp = pData;
                }
                else
                {
                    nRet = ConvertToRGB(m_MyCamera, pData, pFrameInfo.nHeight, pFrameInfo.nWidth, pFrameInfo.enPixelType, IpData);
                    
                    if (MyCamera.MV_OK != nRet)
                    {
                        return;
                    }
                    pTemp = IpData;
                }
                try
                {
                    HOperatorSet.GenImageInterleaved(out Image, (HTuple)pTemp, (HTuple)"rgb", (HTuple)pFrameInfo.nWidth, (HTuple)pFrameInfo.nHeight, -1, "byte", 0, 0, 0, 0, -1, 0);
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            else if (IsMonoPixelFormat(pFrameInfo.enPixelType))
            {
                if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
                {
                    pTemp = pData;
                }
                else
                {
                    nRet = ConvertToMono8(m_MyCamera, pData, IpData, pFrameInfo.nHeight, pFrameInfo.nWidth, pFrameInfo.enPixelType);

                    if (MyCamera.MV_OK != nRet)
                    {
                        return;
                    }
                    pTemp = IpData;
                }
                try
                {
                    HOperatorSet.GenImage1Extern(out Image, "byte", pFrameInfo.nWidth, pFrameInfo.nHeight, pTemp, IntPtr.Zero);
                    //调整图像缩放
                   
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            if (IsUpdateView)
            {
                HalconDisplay(m_Window, Image);
            }
            grabCount++;
            if (grabCount>10)
            {
                grabCount = 0;
            }
            qututureFlag = true;  //取图为真
        }

        public void HalconDisplay(HTuple hWindow, HObject Hobj, HTuple hHeight, HTuple hWidth)
        {
            // ch: 显示 || display
            try
            {
                HOperatorSet.SetPart(hWindow, 0, 0, hHeight - 1, hWidth - 1);// ch: 使图像显示适应窗口大小 || en: Make the image adapt the window size
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return;
            }
            if (hWindow == null)
            {
                return;
            }
            try
            {
                HOperatorSet.DispObj(Hobj, hWindow);// ch 显示 || en: display
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return;
            }
            return;
        }

        public void HalconDisplay(HTuple hWindow, HObject Hobj)
        {
            // ch: 显示 || display
            try
            {
                HTuple height=null,width=null;
                HOperatorSet.GetImageSize(Hobj, out width, out height);
                HOperatorSet.SetPart(hWindow, 0, 0, height - 1, width - 1);// ch: 使图像显示适应窗口大小 || en: Make the image adapt the window size
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return;
            }
            if (hWindow == null)
            {
                return;
            }
            try
            {
                HOperatorSet.DispObj(Hobj, hWindow);// ch 显示 || en: display
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return;
            }
            return;
        }

        private bool IsMonoPixelFormat(MyCamera.MvGvspPixelType enType)
        {
            switch (enType)
            {
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
                    return true;
                default:
                    return false;
            }
        }

        private bool IsColorPixelFormat(MyCamera.MvGvspPixelType enType)
        {
            switch (enType)
            {
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGBA8_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGRA8_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed:
                    return true;
                default:
                    return false;
            }
        }

        public Int32 ConvertToMono8(object obj, IntPtr pInData, IntPtr pOutData, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType)
        {
            if (IntPtr.Zero == pInData || IntPtr.Zero == pOutData)
            {
                return MyCamera.MV_E_PARAMETER;
            }

            int nRet = MyCamera.MV_OK;
            MyCamera device = obj as MyCamera;
            MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();

            stPixelConvertParam.pSrcData = pInData;//源数据
            if (IntPtr.Zero == stPixelConvertParam.pSrcData)
            {
                return -1;
            }

            stPixelConvertParam.nWidth = nWidth;//图像宽度
            stPixelConvertParam.nHeight = nHeight;//图像高度
            stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
            stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);

            stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
            stPixelConvertParam.pDstBuffer = pOutData;//转换后的数据
            stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
            stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * 3);

            nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
            if (MyCamera.MV_OK != nRet)
            {
                return -1;
            }

            return nRet;
        }

        public Int32 ConvertToRGB(object obj, IntPtr pSrc, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType, IntPtr pDst)
        {
            if (IntPtr.Zero == pSrc || IntPtr.Zero == pDst)
            {
                return MyCamera.MV_E_PARAMETER;
            }

            int nRet = MyCamera.MV_OK;
            MyCamera device = obj as MyCamera;
            MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();

            stPixelConvertParam.pSrcData = pSrc;//源数据
            if (IntPtr.Zero == stPixelConvertParam.pSrcData)
            {
                return -1;
            }

            stPixelConvertParam.nWidth = nWidth;//图像宽度
            stPixelConvertParam.nHeight = nHeight;//图像高度
            stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
            stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);

            stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
            stPixelConvertParam.pDstBuffer = pDst;//转换后的数据
            stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
            stPixelConvertParam.nDstBufferSize = (uint)nWidth * nHeight * 3;

            nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
            if (MyCamera.MV_OK != nRet)
            {
                return -1;
            }

            return MyCamera.MV_OK;
        }


    }
}
